<?php

namespace App\Services;

use App\Common\Libs\ArrayHelper;
use App\Common\Libs\IdBuilder;
use App\Consts\GlobalConst;
use App\Consts\GlobalCounterConst;
use App\Consts\GlobalNoteConst;
use App\Consts\GlobalReplyConst;
use App\Events\CacheCounterEvent;
use App\Events\Reply\CreateReplyEvent;
use App\Events\Reply\DelReplyEvent;
use App\Exceptions\Error;
use App\Models\Cache\CacheKey;
use App\Models\Field\ReplyField;
use App\Models\Field\UserField;
use Illuminate\Support\Facades\DB;

/**
 * @package App\Services
 * @see ReplyService
 */
class ReplyService extends BaseService
{
    private $_repository;

    public function __construct()
    {
        parent::__construct();
        $this->_repository = repository()->ReplyRepository;
    }

    /**
     * 通过评论ID获取回复列表
     * @param $searchParams
     * @return array|mixed
     */
    public function getReplyListByCommentId($searchParams)
    {
        $dataProvider = $this->_repository->getRepliesByCommentId($searchParams['comment_id']);
        $pagination = $this->getPagination();
        $replies = $dataProvider->get();
        if (empty($replies)) {
            return $this->searchList['count'];
        }
        $replies = collect($replies->toArray());
        $userIdArr = ArrayHelper::merge($replies->pluck('user_id')->all(), $replies->pluck('to_user_id')->all());
        $users = repository()->UserRepository->getUserByUserIdArr($userIdArr);
        $users = ArrayHelper::index($users, 'user_id');

        // 点赞
        $likes = service()->LikeService->getLikeListByTargetType($searchParams['current_user_id'], GlobalConst::TARGET_TYPE_REPLY);
        $likes = ArrayHelper::index($likes, 'target_id');

        $list = [];
        foreach ($replies as $reply) {
            $reply = ReplyField::format($reply, ReplyField::getFormats(ReplyField::SELF_LIST));
            $reply['is_like'] = (int)(isset($likes[$reply['id']]) && $likes[$reply['id']]['is_deleted'] == GlobalConst::IS_NOT_DELETE);
            $reply['user'] = UserField::format($users[$reply['user_id']], UserField::getFormats(UserField::BASE_INFO));
            $reply['to_user'] = UserField::format($users[$reply['to_user_id']], UserField::getFormats(UserField::BASE_INFO));
            $reply['count'] = service()->CounterService->getTargetCount(
                CacheKey::COUNTER_REPLY, ['reply', 'like'], ['reply_id' => $reply['id']]
            );
            $list[] = $reply;
        }

        return self::outputTotalCountList($dataProvider, $pagination, $list);
    }

    /**
     * 新增回复
     * @param $loadData
     * @return array|bool
     */
    public function createReply($loadData)
    {
        $loadData = ArrayHelper::merge($loadData, [
            'reply_id' => IdBuilder::getUniqueID(),
            'is_deleted' => GlobalConst::IS_NOT_DELETE
        ]);

        $loadData = ArrayHelper::merge($loadData, $this->getReplyParentInfo($loadData['parent_id']));
        ArrayHelper::remove($loadData, 'parent_id');

        // 私密笔记不可回复
        if ($loadData['target_type'] == GlobalConst::TARGET_TYPE_NOTE) {
            $note = repository()->NoteRepository->getNoteById($loadData['target_id']);
            if ((!$note || ($note && $note->is_deleted == GlobalConst::IS_DELETED) || ($note && $note->is_public == GlobalNoteConst::IS_NOT_PUBLIC)) && $loadData['user_id'] != $note->user_id) {
                return false;
            }
        }

        // 评论删除不可恢复
        $comment = repository()->CommentRepository->getComment($loadData['comment_id']);
        if ($comment && $comment->is_deleted == GlobalConst::IS_DELETED) {
            return false;
        }

        DB::beginTransaction();
        try {
            // 新增回复
            $reply = repository()->ReplyRepository->createReply($loadData);
            $data = [
                'comment_id' => $loadData['comment_id'],
                'reply_id' => $loadData['reply_id'],
                'to_reply_id' => $loadData['to_reply_id'],
                'user_id' => $loadData['user_id'],
                'to_user_id' => $loadData['to_user_id'],
                'target_id' => $loadData['target_id'],
                'target_type' => $loadData['target_type'],
            ];

            // 【暂时】新增索引表记录
            repository()->CommentRepository->addIndexComment(ArrayHelper::merge($data, [
                'type' => GlobalConst::TARGET_TYPE_REPLY,
            ]));

            // 同步更新主体计数
            $this->syncCounterFromCache($loadData['comment_id'], $loadData['target_id'], $loadData['target_type']);

            /**
             * 队列做以下几件事：
             *  1. 修改【评论】是否为主体发布者发布
             *  2. 发送消息
             *  3. 记录日志
             */
            CreateReplyEvent::dispatch($reply);

            DB::commit();

            return ArrayHelper::merge($reply->commonFormat(), [
                'id' => $loadData['reply_id']
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return false;
        }
    }

    /**
     * 删除回复
     * @param $replyId
     * @param $currentUserId
     * @return \Illuminate\Http\JsonResponse|array
     */
    public function deleteReply($replyId, $currentUserId)
    {
        DB::beginTransaction();
        try {
            // 获取回复
            $reply = repository()->ReplyRepository->getReplyByReplyId($replyId);
            if (!$reply || $reply->user_id !== $currentUserId) {
                return Error::handle(lang('Unauthorized'));
            }

            // 删除回复
            repository()->ReplyRepository->deleteReply($reply);

            // 【暂时】删除索引表记录
            repository()->ReplyRepository->deleteIndexComment($reply);

            // 事件同步更新主体计数
            $this->syncCounterFromCache($reply['comment_id'], $reply['target_id'], $reply['target_type'], GlobalCounterConst::DECREASE);

            // 异步更新【评论】的【可见性】和【删除态】
            DelReplyEvent::dispatch($reply);

            DB::commit();

            return $reply->commonFormat();
        } catch (\Exception $e) {
            DB::rollBack();
            return Error::handle(lang('Unauthorized'));
        }
    }

    /**
     * 同步回复的主体和评论的缓存计数
     * @param $commentId
     * @param $targetId
     * @param $targetType
     * @param int $trend
     * @return bool
     */
    public function syncCounterFromCache($commentId, $targetId, $targetType, $trend = GlobalCounterConst::INCREASE)
    {
        // 修改评论的回复数
        CacheCounterEvent::dispatch([
            'key_params' => ['comment_id' => $commentId],
            'cache_key' => CacheKey::COUNTER_COMMENT,
            'values' => GlobalCounterConst::COUNT_REPLY,
            'trend' => $trend
        ]);

        // 修改主体的回复数
        $data = [];
        if ($targetType == GlobalConst::TARGET_TYPE_NOTE) {
            $data = [
                'key_params' => ['note_id' => $targetId],
                'cache_key' => CacheKey::COUNTER_NOTE,
                'values' => GlobalCounterConst::COUNT_REPLY,
                'trend' => $trend
            ];
        }

        if ($targetType == GlobalConst::TARGET_TYPE_DYNAMIC) {
            $data = [
                'key_params' => ['dynamic_id' => $targetId],
                'cache_key' => CacheKey::COUNTER_DYNAMIC,
                'values' => GlobalCounterConst::COUNT_REPLY,
                'trend' => $trend
            ];
        }

        if ($data) {
            CacheCounterEvent::dispatch($data);
        }

        return true;
    }

    /**
     * 获取回复的主体的用户
     * @param $reply
     * @return bool|string
     */
    public function getReplyTargetUserId($reply)
    {
        $receiveUserId = '';
        if ($reply['target_type'] == GlobalConst::TARGET_TYPE_NOTE) {
            $note = repository()->NoteRepository->getNoteByNoteId($reply['target_id']);
            if ($note) {
                $receiveUserId = $note['user_id'];
            }
        }
        if ($reply['target_type'] == GlobalConst::TARGET_TYPE_DYNAMIC) {
            $dynamic = repository()->DynamicRepository->getDynamicById($reply['target_id']);
            if ($dynamic) {
                $receiveUserId = $dynamic['user_id'];
            }
        }

        return $receiveUserId ?? false;
    }

    /**
     * 获取回复的对象信息
     *  1. 回复的是评论
     *  2. 回复的是回复
     * @param $parentId
     * @return array
     */
    private function getReplyParentInfo($parentId)
    {
        $comment = repository()->CommentRepository->getComment($parentId);
        // 说明回复的是回复
        if (!$comment) {
            $reply = repository()->ReplyRepository->getReplyByReplyId($parentId);
            if ($reply) {
                return [
                    'comment_id' => $reply['comment_id'],
                    'target_id' => $reply['target_id'],
                    'target_type' => $reply['target_type'],
                    'to_reply_id' => $reply['reply_id'],
                    'to_user_id' => $reply['user_id'],
                    'type' => GlobalReplyConst::REPLY_TYPE_REPLY,
                ];
            }
        }

        return [
            'comment_id' => $comment['comment_id'],
            'target_id' => $comment['target_id'],
            'target_type' => $comment['target_type'],
            'to_reply_id' => '',
            'to_user_id' => $comment['user_id'],
            'type' => GlobalReplyConst::REPLY_TYPE_COMMENT,
        ];
    }
}
